package io.lvdaxian.mybatis10.builder;

import io.lvdaxian.mybatis10.mapping.ParameterMapping;
import io.lvdaxian.mybatis10.mapping.SqlSource;
import io.lvdaxian.mybatis10.parsing.GenericTokenParser;
import io.lvdaxian.mybatis10.parsing.TokenHandler;
import io.lvdaxian.mybatis10.reflection.MetaClass;
import io.lvdaxian.mybatis10.reflection.MetaObject;
import io.lvdaxian.mybatis10.session.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class SqlSourceBuilder extends BaseBuilder {
  
  private static final Logger logger = LoggerFactory.getLogger(SqlSourceBuilder.class);
  private static final String parameterProperties = "javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName";
  
  public SqlSourceBuilder(Configuration configuration) {
    super(configuration);
  }
  
  public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) {
    ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
    GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
    String sql = parser.parse(originalSql);
    // 返回静态 SQL
    return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
  }
  
  private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {
    
    private final List<ParameterMapping> parameterMappings = new ArrayList<>();
    private final Class<?> parameterType;
    private MetaObject metaParameters;
    
    public ParameterMappingTokenHandler(Configuration configuration, Class<?> parameterType, Map<String, Object> additionalParameters) {
      super(configuration);
      this.parameterType = parameterType;
      this.metaParameters = configuration.newMetaObject(additionalParameters);
    }
    
    public List<ParameterMapping> getParameterMappings() {
      return parameterMappings;
    }
    
    @Override
    public String handleToken(String content) {
      parameterMappings.add(buildParameterMapping(content));
      return "?";
    }
    
    // 构建参数映射
    private ParameterMapping buildParameterMapping(String content) {
      // 先解析参数映射,就是转化成一个 HashMap | #{favouriteSection,jdbcType=VARCHAR}
      Map<String, String> propertiesMap = new ParameterExpression(content);
      String property = propertiesMap.get("property");
      Class<?> propertyType;
      
      // 判断 类型注册器中是否存在该类
      if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
        propertyType = parameterType;
      } else if (null != property) {
        // 利用反射 构建这个对象 parameterType
        MetaClass metaClass = MetaClass.forClass(parameterType);
        // 判断其 是否存在getter 方法
        if (metaClass.hasGetter(property)) {
          // 拿到getter类型
          propertyType = metaClass.getGetterType(property);
        } else {
          propertyType = Object.class;
        }
      } else {
        propertyType = Object.class;
      }
      
      
      logger.info("构建参数映射 property：{} propertyType：{}", property, propertyType);
      ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
      return builder.build();
    }
  }
}
